#pragma once
#include "../source/message.hpp"
#include "../source/net.hpp"
#include "../source/dispacher.hpp"
#include "Requestor.hpp"

namespace ns_client_topic
{
    class TopicManager
    {
    public:
        using ptr = std::shared_ptr<TopicManager>;
        using subcallback = std::function<void(const std::string&,const std::string&)>; //void(topic_name,msg)
        TopicManager(ns_Req::Requestor::ptr requestor)
        :_requestor(requestor)
        {};
        //给用户提供的
        bool Create(const BaseConnection::ptr& conn,const std::string& topic_name)
        {
            return CommRequest(conn,topic_name,TopicOptype::TOPIC_CREATE);
        }
        bool Remove(const BaseConnection::ptr& conn,const std::string& topic_name)
        {
            return CommRequest(conn,topic_name,TopicOptype::TOPIC_REMOVE);
        }
        bool Subscribe(const BaseConnection::ptr& conn,const std::string& topic_name,const subcallback& scb)
        {
           //如果刚订阅就有消息发布，那就得调用用户给的回调进行处理，那就得先把回调的映射存起来。
            Addhashs(topic_name,scb);
            bool ret = CommRequest(conn,topic_name,TopicOptype::TOPIC_SUBSCRIBE);
           //如果请求主题订阅失败，那上面的映射关系又得去除,在下面封装一下关于映射增删查的操作
            if(ret == false)
            {
                Removehashs(topic_name);
                return false;
            }
            return true;
        }
        bool Cancel(const BaseConnection::ptr& conn,const std::string& topic_name)
        {
            return CommRequest(conn,topic_name,TopicOptype::TOPIC_CANCEL);
        }
        bool Publish(const BaseConnection::ptr& conn,const std::string& topic_name,const std::string& msg)
        {
            return CommRequest(conn,topic_name,TopicOptype::TOPIC_PUBLISH,msg);
        }
        //给dispacher的，用于处理服务端推过来的消息发布请求，处理完也要给予响应
        void OnPublish(const BaseConnection::ptr& conn,const TopicRequest::ptr& topic_msg)
        {
            if(topic_msg->GetOtype() != TopicOptype::TOPIC_PUBLISH)
            {
                LOG(ERROR,"此消息不是消息发布请求!!!");
                return; 
            }
            std::string topic_name = topic_msg->GetKey();
            std::string msg = topic_msg->GetMessage();
            subcallback scb = Gethashs(topic_name);
            if(scb == nullptr)
            {
                LOG(ERROR,"没有找到该主题的消息处理回调，无法操作!!!");
                return;
            }
            return scb(topic_name,msg);
        }
    private:
        void Addhashs(const std::string& topic_name,const subcallback& scb)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _hashs.insert(std::make_pair(topic_name,scb));
        }
        void Removehashs(const std::string& topic_name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _hashs.erase(topic_name);
        }
        subcallback Gethashs(const std::string& topic_name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _hashs.find(topic_name);
            if(it == _hashs.end())
                return subcallback();
            return it->second;
        }
        bool CommRequest(const BaseConnection::ptr& conn,const std::string& topic_name,TopicOptype otype,const std::string& msg = "")
        {
             //1.根据请求类型构建对应请求消息
            auto topic_msg = MessageFactory::Createmsg<TopicRequest>();
            //2.填充字段
            topic_msg->Setid(ns_uuid::UUIDUtil::uuid());
            topic_msg->SetKey(topic_name);
            if(otype == TopicOptype::TOPIC_PUBLISH)
                topic_msg->SetMessage(msg);
            topic_msg->SetMtype(Mtype::TOPIC_REQ);
            topic_msg->SetOtype(otype);
            //3.发送请求，接收响应并判断
            BaseMessage::ptr rsp_msg;
            bool ret = _requestor->Send(conn,topic_msg,rsp_msg);
            if(ret == false)
            {
                LOG(ERROR,"主题操作失败!!!");
                return false;
            }
            auto topic_rsp = std::dynamic_pointer_cast<TopicResponse>(rsp_msg);
            if(!topic_msg)
            {
                LOG(ERROR,"主题操作时,rsp_msg向下转换失败!!!");
                return false;
            }
            if(topic_rsp->GetRcode() != Rcode::RCODE_OK)
            {
                LOG(ERROR,"主题操作未成功!!!");
                return false;
            }
            return true;

        }
        std::mutex _mutex;
        std::unordered_map<std::string,subcallback> _hashs;  //主题和它的处理回调的关联关系
        ns_Req::Requestor::ptr _requestor;
    };
}
